package com.yoki.cloud.common.protocol.portal.msg;


import com.yoki.cloud.common.protocol.portal.msg.attr.MsgAttr;
import lombok.Data;
import lombok.ToString;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Sky$
 * @Description: TODO
 * @date 2017/10/24$ 19:16$
 */
@Data
@ToString
public abstract class AbstractPortalMsg {

    protected static Integer HEADER_LENGTH = 16;

    protected int ver;
    protected int type;
    protected int papChap = 1;
    protected int rsvd = 0;
    protected int serialNo;
    protected int reqId;
    protected String userIp;
    protected int userPort = 0;
    protected int errCode;
    protected int attrNum;
    protected List<MsgAttr> attrList = new ArrayList<>();

    public List<MsgAttr> addMsgAttr(MsgAttr attr) {
        if (null == attrList) {
            attrList = new ArrayList<>();
        }
        attrList.add(attr);
        return attrList;
    }

    /**
     * 根据头部所有字段获取头部byte数组
     *
     * @return
     */
    protected byte[] getHander16Bytes() {
        byte[] b = new byte[16];
        b[0] = (byte) (ver & 0xff);
        b[1] = (byte) (type & 0xff);
        b[2] = (byte) (papChap & 0xff);
        b[3] = (byte) (rsvd & 0xff);
        b[4] = (byte) (serialNo >> 8 & 0xff);
        b[5] = (byte) (serialNo & 0xff);
        b[6] = (byte) (reqId >> 8 & 0xff);
        b[7] = (byte) (reqId & 0xff);
        byte[] ip = ipv4Address2BinaryArray(userIp);
        System.arraycopy(ip, 0, b, 8, 4);
        b[12] = (byte) (userPort >> 8 & 0xff);
        b[13] = (byte) (userPort & 0xff);
        b[14] = (byte) (errCode & 0xff);
        b[15] = (byte) (attrNum & 0xff);
        return b;
    }

    /**
     * 获取TLV属性列表字节数组
     *
     * @return
     */
    protected byte[] getAttrBytes() {
        int attrByteNum = 0;
        if (attrList != null && !attrList.isEmpty()) {
            for (MsgAttr a : attrList) {
                attrByteNum += a.getAttrLen();
            }
        }
        byte[] b = new byte[attrByteNum];
        int index = 0;
        if (attrList != null && !attrList.isEmpty()) {
            for (MsgAttr a : attrList) {
                System.arraycopy(a.getByteValues(), 0, b, index, a.getByteValues().length);
                index += a.getByteValues().length;
            }
        }
        return b;
    }

    /**
     * 抽象方法<br>
     * 将整个实体类转换为字节数组
     *
     * @return
     */
    public abstract byte[] toByteArray();

    /**
     * 抽象方法<br>
     * 将byte数值解析成本实体类
     *
     * @param input
     */
    public abstract void parse(byte[] input);

    /**
     * 通过字节数组解析实体类头部
     *
     * @param input
     */
    protected void parseHeader(byte[] input) {
        this.setVer(input[0]);
        this.setType(input[1]);
        this.setPapChap(input[2]);
        this.setRsvd(input[3]);

        this.setSerialNo(((input[4] << 8) | input[5]) & 0xffff);
        this.setReqId(((input[6] << 8) | input[7]) & 0xffff);

        this.setUserIp((input[8] & 0xff) + "." + (input[9] & 0xff) + "." + (input[10] & 0xff) + "." + (input[11] & 0xff));
        this.setUserPort((input[12] << 8) | input[13]);

        this.setErrCode(input[14]);
        this.setAttrNum(input[15]);
    }

    /**
     * 通过字节数组解析TLV属性列表
     *
     * @param attrBytes
     * @param attrNum
     */
    protected void parseAttr(byte[] attrBytes, int attrNum) {
        List<MsgAttr> attrList = new ArrayList<MsgAttr>();
        int count = attrNum;
        if (count > 0) {
            int t = 0;
            for (int i = 0; i < count; i++) {
                int attrType = attrBytes[t];
                int attrLen = attrBytes[t + 1];
                byte[] d = new byte[attrLen - 2];
                System.arraycopy(attrBytes, t + 2, d, 0, attrLen - 2);
                MsgAttr c = new MsgAttr(attrType, new String(d));
                attrList.add(c);
                t += c.getAttrLen();
            }
        }
        this.setAttrList(attrList);
    }

    protected byte[] ipv4Address2BinaryArray(String ipAdd) {
        byte[] binIP = new byte[4];
        String[] strs = ipAdd.split("\\.");
        for (int i = 0; i < strs.length; i++) {
            binIP[i] = (byte) Integer.parseInt(strs[i]);
        }
        return binIP;
    }


}
